/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2020年9月11日
 */
package com.massyframework.beanskin.spring.beancontext.util;


import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.springframework.core.io.Resource;
import org.springframework.core.io.UrlResource;

import com.massyframework.beanskin.assembly.Assembly;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;

/**
 * @author huangkh
 *
 */
public class ConfigLocationsUtils {

	private static final String ASSEMBLY_XML = "BEANSKIN-INF/assembly.xml";
    public static String[] DEFAULT_XML = new String[]{"classpath*:/BEANSKIN-INF/spring-context.xml"};

    /**
     * 获取配置资源
     * @param assembly {@link ServiceExportableModule}
     * @param defaultResource {@link Resource}数组
     * @return {@link Resource}数组
     * @throws URISyntaxException URI语法错误
     */
    public static Resource[] getResources(Assembly assembly, String[] defaultResource) {
        String[] configLocations =
                assembly.getConfig().getConfigLocations();
        if (configLocations.length == 0){
            configLocations = defaultResource;
        }
        

        try {
            ClassLoader assemblyLoader = assembly.getModuleClassLoader();

            URL assemblyXmlUrl =
                    assemblyLoader.getResource(ASSEMBLY_XML);
            URI base = assemblyXmlUrl.toURI();

            Resource[] result = new Resource[configLocations.length];
            int size = configLocations.length;
            for (int i = 0; i < size; i++) {
                String location = configLocations[i];
                result[i] = resolveResource(base, location, assembly);
            }
            return result;
        }catch(Exception e){
            Logger logger = assembly.getLogger();
            if (logger.isErrorEnabled()){
                logger.error("get configLocation resource failed.", e);
            }
            return new Resource[0];
        }
    }

    /**
     * 解析所有配置文件路径
     * @param assembly {@link Assembly}, 装配件
     * @param defaultResource {@link String}, 缺省的资源你路径
     * @return {@lnk String}数组
     */
    public static String[] resolveConfigLocations(Assembly assembly, String[] defaultResource){
        String[] configLocations =
                assembly.getConfig().getConfigLocations();
        if (configLocations.length == 0){
            return defaultResource;
        }

        try {
            URI base = new URI(ASSEMBLY_XML);

            String[] result = new String[configLocations.length];
            int size = configLocations.length;
            for (int i = 0; i < size; i++) {
                String location = configLocations[i];
                URI uri = resolveURI(base, location, assembly);
                if (uri != null){
                    String schema = uri.getScheme();
                    if (schema == null) {
                        result[i] = "classpath:".concat(uri.getPath());
                    }else{
                        result[i] = uri.toURL().toExternalForm();
                    }
                }
            }
            return result;
        }catch(Exception e){
            Logger logger = assembly.getLogger();
            if (logger.isErrorEnabled()){
                logger.error("get configLocation resource failed.", e);
            }
            return new String[0];
        }
    }

    /**
     * 解析URI
     * @param base {@link URI}, 基本的路径
     * @param location {@link String}, 相对路径
     * @param assembly {@link Assembly}, 装配件
     * @return {@link URI}
     */
    private static URI resolveURI(URI base, String location, Assembly assembly){
        try {
            if (location.startsWith("./") || location.startsWith("../")) {
                String schema = base.getScheme();
                if (StringUtils.equals(schema, "jar")) {
                    String basePath = base.toString();
                    int pos = StringUtils.indexOf(basePath, "!/");
                    String subPath = StringUtils.substring(basePath, pos + 1 );
                    URI newURI = new URI(subPath).resolve(location);
                    return newURI;
                }else{
                    URI newURI = base.resolve(location);
                    return newURI;
                }
            }
            return new URI(location);
        }catch(Exception e){
            Logger logger = assembly.getLogger();
            if (logger.isErrorEnabled()){
                logger.error("resolve uri failed.", e);
            }
            return null;
        }
    }

    /**
     * 解析资源
     * @param base {@link URI}, 基本的路径
     * @param location {@link String}, 相对路径
     * @param assembly {@link Assembly}, 装配件
     * @return {@link URI}
     */
    private static Resource resolveResource(URI base, String location, Assembly assembly){
        URI uri = resolveURI(base, location, assembly);
        try {
            return new UrlResource(uri.toURL());
        } catch (MalformedURLException e) {
            Logger logger = assembly.getLogger();
            if (logger.isErrorEnabled()){
                logger.error("resolve uri failed.", e);
            }
            return null;
        }
    }
}
